package zhongbo.javaweb.instagram.util.dns;

import lombok.Builder;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.conn.DnsResolver;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * 说明：dns 解析器 for HttpClient
 * 使用自定义的dns服务器地址, 解决在 Termux 中:
 * 因 linux 系统或 host 文件配置问题导致的无法解析域名的问题
 * <p>
 * #link https://blog.csdn.net/rzleilei/article/details/19546903
 *
 * @author 钟波notebook
 * @since 2020年08月16日 星期日 17:11:54
 */
@Slf4j
@Builder
public class CustomDnsResolver implements DnsResolver {

    /**
     * dns服务器列表
     */
    private String[] dnsServers;

    /**
     * dns超时时间
     */
    public int timeoutMs;

    /**
     * dns重试次数
     */
    public int retryCount;


    private static final String[] DEFAULT_DNS_SERVERS = new String[]{"8.8.8.8", "114.114.114.114"};
    private static final int DEFAULT_TIMEOUT_MS = 1000;
    private static final int DEFAULT_RETRY_COUNT = 5;
    private static final String HTTP_PROTOCOL_HTTP = "http";
    private static final String HTTP_PROTOCOL_HTTPS = "https";
    private static final String SIGN_SEPARATOR = "/";

    @Override
    public InetAddress[] resolve(String host) throws UnknownHostException {

        if (null == dnsServers || dnsServers.length == 0) {
            log.debug("use default dns : {} resolving host: {}", DEFAULT_DNS_SERVERS, host);
            dnsServers = DEFAULT_DNS_SERVERS;
        }

        if (timeoutMs <= 0) {
            log.debug("use default timeoutMs : {} you timeout: {}", DEFAULT_TIMEOUT_MS, timeoutMs);
            timeoutMs = DEFAULT_TIMEOUT_MS;
        }

        if (retryCount <= 0) {
            log.debug("use default retryCount : {} you retryCount: {}", DEFAULT_RETRY_COUNT, retryCount);
            retryCount = DEFAULT_RETRY_COUNT;
        }

        String domain = getDomain(host);
        if (DnsUtil.isIPv4Address(host)) {
            log.debug("dns seek: {} isIPv4, host: {}", host, host);
            return InetAddress.getAllByName(host);
        }
        Set<String> allIp = DnsUtil.getAllIp(domain, dnsServers, timeoutMs, retryCount);
        InetAddress[] inetAddresses = {};
        List<InetAddress> result = new ArrayList<>();
        for (String ip : allIp) {
            result.add(InetAddress.getByName(ip));
        }
        if (result.size() == 0) {
            log.warn("解析ip地址失败! 尝试用系统dns解析!");
            InetAddress[] allByName = InetAddress.getAllByName(host);
            log.warn("dns seek: {} host: {}", allByName, host);
            return allByName;
        }
        return result.toArray(inetAddresses);
    }

    /**
     * 获取一个网址的域名部分
     *
     * @param host 网址
     * @return domain 域名
     */
    private static String getDomain(String host) {
        host = host.toLowerCase();
        if (host.startsWith(HTTP_PROTOCOL_HTTP)) {
            host = host.replace(HTTP_PROTOCOL_HTTP, "");
        }
        if (host.startsWith(HTTP_PROTOCOL_HTTPS)) {
            host = host.replace(HTTP_PROTOCOL_HTTPS, "");
        }
        if (host.contains(SIGN_SEPARATOR)) {
            host = host.split(SIGN_SEPARATOR)[0];
        }
        return host;
    }
}
